#______________________________________________________________________________#
#                           --PARSER GRAMATICA---                              #
#    # Grupo: Grog xD                                                          #
#    # Integrantes:                                                            #
#           -Alejandro Julian                                                  #
#           -Marcos Federico Mandrille                                         #
#           -Mauricio Nazzetta                                                 #
#           -Nicolas Nocete                                                    #
#______________________________________________________________________________#
#   Inclusion de unidades requeridas
from Pascal_Lex import tokens           #Desde nuestro lexer trae los tokens necesarios...
import PLY.yacc as yacc                 #Unidad proveniente del yacc [Guardada en la carpeta PLY, que posee __init__]...
import Pascal_ICML as icml              #Todo el manejo del elemental tree________
import Pascal_TS as clases              #Unidad creada por nosotros con las clases que usara la TS
import Pascal_Error as error            #Unidad encargada de impresion de errores
import Pascal_Subprograms as subprograms#Unidad con funciones default de Pascal
import Pascal_Mantenimiento as clean    #Unidad de limpieza de carpetas...

#   Coloco la procedencia de operadores matematicos
precedence =(('left','tkPlus','tkMinus'),('left','tkMod','tkDiv'))

# ############################################################################ #
#                           Gramatica Pascal by us!                            #
def p_inicio(p):
    '''inicio : programa tkSemiColon unidades declaraciones tkBegin sentencias tkEnd tkPoint'''
    icml.Imprimir(p)
    print(source_filename + " Parseado con exito")

def p_programa(p):
    '''programa : tkProgram id parametros'''
    print("Inicio de parseo de: " + p[2])
    p.program = p[2]
    icml.Crear(p)
    subprograms.Subprogram_Loader(p)
#______________________________________________________________________________#
#                   PARAMETROS
def p_parametros(p):
    '''parametros : tkLparen parametros2 tkRparen
    | lambda'''

def p_parametros2(p):
    '''parametros2 : parametros2 tkSemiColon parametros3
    | parametros3'''

def p_parametros3(p):
    ''' parametros3 : lista_ids tkColon tipos'''
    lista = p[1].split(",")
    lista.reverse()
    for x in lista:
       p.parser.actual.insertar_parametro(clases.C_elemento(x,"param",p[3].tipo_dato,None,p[3].dimension))
       icml.Encontrar_Cabezal(p,"param")
       icml.Crear_Cuerpo(p.head,"param",[("type",p[3].tipo_dato),("name",x)])

def p_lista_ids(p):
    '''lista_ids : lista_ids tkComma id
    | id'''
    if len(p)==4: p[0] = p[3] + "," + p[1]
    if len(p)==2: p[0] = p[1]

def p_tipos(p):
    '''tipos : tkRealV
    | tkCharV
    | tkIntegerV
    | tkFloatV
    | tkStringV
    | tkBooleanV
    | tkByteV
    | tkLongIntV
    | tkDoubleV
    | tkSingleV
    | tkWordV
    | id lambda
    | tkArray tkLbrac lista_rango tkRbrac tkOf tipos'''
    if len(p)==2: p[0]=clases.C_elemento(None,'type',p[1],None,None)
    elif len(p)==3: p[0]=clases.C_elemento(p[1],"type",p[1],None,None)
    elif len(p)==7:
        p[0]= clases.C_elemento(None,'type','array',None,p[3].dato,p[6].tipo_dato)
        p[0].fruta = p[3].fruta
        p[0].fruta.tag = p[6].tipo_dato
        if p[6].tipo_dato == "array": p[0].fruta.insert(len(p[0].fruta.getchildren()),p[6].fruta)

def p_lista_rango(p):
    '''lista_rango : rango tkComma lista_rango
    | rango'''
    if len(p)==2:
        p[0] = clases.C_cargador(None)
        p[0].fruta = icml.e.Element("array")
        p[0].fruta.insert(0,p[1].fruta)
    elif len(p)==4:
        p[3].fruta.insert(0,p[1].fruta)
        p[0] = p[3]

def p_rango(p):
    '''rango : numero tkDotDot numero
    | id'''
    if len(p)==4:
        if p[1] > p[3]: error.error16(p)
        p[0] = clases.C_cargador("[" + str(p[1]) + "," + str(p[3]) + "]")
        p[0].fruta = icml.e.Element("range")
        icml.Crear_Cuerpo(p[0].fruta,"value",[("inicio",p[1])])
        icml.Crear_Cuerpo(p[0].fruta,"value",[("fin",p[3])])
    elif len(p)==2:
        p[0] = clases.C_cargador(p[1])
        p[0].fruta = icml.e.Element("range")
        icml.Crear_Cuerpo(p[0].fruta,"range",[("var",p[1])])

def p_numero(p):
    '''numero : tkByte
    | tkInteger'''
    p[0] = p[1]
#______________________________________________________________________________#
#                           ------DECLARACIONES------                          #
def p_declaraciones(p):
    '''declaraciones : constantes types variables subprogramas'''
    if p.parser.actual.nombre == "main": p.head = icml.e.SubElement(p.root,"begin")
    else: p.head = icml.e.SubElement(icml.Encontrar_Cabezal_Subprogram(p),"begin")
    print("Declaracion de elementos en: " + p.parser.actual.nombre )
    #unidades :donde declaro los uses
    #constantes: Const
    #types: Tipos definidos por el usuario
    #variables: Vars
    #subprogramas: funciones y procedimientos
#______________________________________________________________________________#
#                       ------Uses declaration!------
def p_unidades(p):
    '''unidades : tkUses lista_unidades tkSemiColon
    | lambda'''
    if len(p)== 2: icml.Encontrar_Cabezal(p,"uses")

def p_lista_unidades(p):
    '''lista_unidades : lista_unidades tkComma id
    | id'''
    if len(p)== 4:
        p.parser.actual.insertar_elemento(clases.C_elemento(p[3],"unit","unit",None,None))
        icml.Encontrar_Cabezal(p,"uses")
        icml.Crear_Cuerpo(p.head,"unit",[("name",p[3])])
    else:
        p.parser.actual.insertar_elemento(clases.C_elemento(p[1],"unit","unit",None,None))
        icml.Encontrar_Cabezal(p,"uses")
        icml.Crear_Cuerpo(p.head,"unit",[("name",p[1])])
        #En este paso voy dejando una coma y otro unidad hasta que solo viene el ;
#______________________________________________________________________________#
#                       ------Constantes!------
def p_constantes(p):
    '''constantes : tkConst constantes2
    | lambda'''

def p_constantes2(p):
    '''constantes2 : constantes2 constantes3
    | constantes3'''

def p_constantes3(p):
    '''constantes3 : id tkEqual operacion tkSemiColon'''
    p.parser.actual.insertar_elemento(clases.C_elemento(p[1],"const",p[3].tipo_dato,None,None))
    icml.Encontrar_Cabezal(p,"consts")
    icml.Crear_Cuerpo(p.head,"const",[("value",p[3].nombre),("type",p[3].tipo_dato),("name",p[1])])

def p_valor(p): #El NT valor puede derivar en las diferentes variaciones...
    '''valor : tkReal
    | tkInteger lambda
    | tkFloat  lambda lambda
    | tkString lambda lambda lambda
    | tkBoolean lambda lambda lambda lambda
    | tkByte lambda lambda lambda lambda lambda'''
    if len(p)==2: p[0]= clases.C_elemento(str(p[1]),"const","real",p[1],None)
    if len(p)==3: p[0]= clases.C_elemento(str(p[1]),"const","integer",p[1],None)
    if len(p)==4: p[0]= clases.C_elemento(str(p[1]),"const","float",p[1],None)
    if len(p)==5: p[0]= clases.C_elemento(p[1],"const","string",p[1],None)
    if len(p)==6: p[0]= clases.C_elemento(str(p[1]),"const","boolean",p[1],None)
    if len(p)==7: p[0]= clases.C_elemento(str(p[1]),"const","byte",p[1],None)
#______________________________________________________________________________#
#               ------Tipos definidos por el usuario------
def p_types(p):
    '''types : tkType types2
    | lambda'''

def p_types2(p):
    '''types2 : types2 types3
    | types3'''

def p_types3(p):
    '''types3 : id tkEqual tipos tkSemiColon
    | id tkEqual tkStringV tkLbrac numero tkRbrac tkSemiColon
    | id tkEqual tkLparen lista_identificadores tkRparen tkSemiColon
    | id tkEqual numero tkDotDot numero tkSemiColon lambda lambda
    | id tkEqual tkRecord types4 tkEnd tkSemiColon lambda lambda lambda'''
    p[0]=p[1]
    icml.Encontrar_Cabezal(p,"types")
    if len(p)==5:
        p[0]=clases.C_elemento(p[1],p[3].tipo_token,p[3].tipo_dato,None,p[3].dimension) # tcosa = tipo
        #Agregamos el tipo a las listas -> Insercion: Lista[x:x] = Nuevo_item
        if p[3].tipo_dato in clases.Cadenas: clases.Cadenas[clases.Cadenas.index(p[3].tipo_dato):clases.Cadenas.index(p[3].tipo_dato)]= [p[1]]
        if p[3].tipo_dato in clases.Numericos: clases.Numericos[clases.Numericos.index(p[3].tipo_dato):clases.Numericos.index(p[3].tipo_dato)]= [p[1]]
        icml.Crear_Cuerpo(p.head,"type",[("name",p[1]),("type",p[3].tipo_dato)])
    if len(p)==8: # tPalabra = String[20]
        p[0]=clases.C_elemento(p[1],"type","string",None,None)
        clases.Cadenas[1:1] = [p[1]]
        icml.Crear_Cuerpo(p.head,"type",[("name",p[1]),("type","string"),("tamano",p[5])])

    if len(p)==7: # tSemana = (lunes,martes,miercoles)
        p[0]= clases.C_elemento(p[1],"type","enumeracion",None,"")
        for x in reversed(p[4].split(",")):
            p[0].dimension += x + ","
        p[0].dimension = "[" + p[0].dimension[0:len(p[0].dimension)-1] + "]"
        icml.Crear_Cuerpo(p.head,"type",[("name",p[1]),("type","enumeracion"),("range",p[0].dimension)])

    if len(p)==9: # tHoras = 1..23
        p[0] = clases.C_elemento(p[1],"type","integer",None,(str(p[3]) + ".." + str(p[5])))
        icml.Crear_Cuerpo(p.head,"type",[("name",p[1]),("type","integer"),("range",p[0].dimension)])
    if len(p)==10: #El que tiene RECORD y define un registro...
        p[0]= clases.C_type(p[1],p.parser.actual)
        p.head = icml.e.SubElement(p.head,"type")
        p.head.set("name",p[1])
        for x in p[4]:
            p[0].insertar_elemento(x)
            icml.Crear_Cuerpo(p.head,"attrib",[("name",x.nombre),("type",x.tipo_dato)])
    p.parser.actual.insertar_elemento(p[0])

def p_types4(p):
    '''types4 : id tkColon tipos tkSemiColon
    | types4 id tkColon tipos tkSemiColon'''
    if len(p)==5: p[0] = [clases.C_elemento(p[1],"type",p[3].tipo_dato,None,p[3].dimension,p[3].oftype)]
    if len(p)==6:
        p[1].append(clases.C_elemento(p[2],"type",p[4].tipo_dato,None,p[4].dimension,p[4].oftype))
        p[0] = p[1]


#______________________________________________________________________________#
#                       ------Variables------
def p_variables(p):
    '''variables : tkVar lista_variables
    | lambda'''
    p.head = p.root.find("subprogram") #Find busca en el root, el elemento que tenga de tag el parametro pasado
    if p.head == None: #Si find no encontro nada, devuelve "None"
        p.head = icml.e.SubElement(p.root,"subprogram")  #Si nunca se creo, lo hacemos
        p.head.tag = "subprogram" #Creamos el tag para que desp lo encuentre :D

def p_lista_variables(p):
    '''lista_variables : lista_variables declaracion_variable
    | declaracion_variable'''

def p_declaracion_variable(p):
    '''declaracion_variable : lista_identificadores tkColon tipos tkSemiColon'''
    for id in reversed(p[1].split(",")):
        item = clases.C_elemento(id,"var",p[3].tipo_dato,None,p[3].dimension,None)
        p.parser.actual.insertar_elemento(item)
        icml.Encontrar_Cabezal(p,"vars")
        if p[3].oftype == None: icml.Crear_Cuerpo(p.head,"var",[("name",item.nombre),("date_type",p[3].tipo_dato)]) #Si NO es un array:
        else: #es por que es un array
            item.oftype = p[3].oftype
            head_array = icml.e.SubElement(p.head,"var")
            head_array.set("name",item.nombre)
            head_array.set("type",p[3].tipo_dato)
            head_array.set("date_type",p[3].oftype)
            head_array.insert(0,p[3].fruta)

def p_lista_identificadores(p):
    '''lista_identificadores : id tkComma lista_identificadores
    |  id''' #No la pude hacer con recursividad a izquierda...
    if len(p)==2: p[0] = p[1]
    if len(p)==4: p[0] = p[3] + "," + p[1]
# ############################################################################ #
#        ---------Declaracion de procedimientos y funciones-----------
def p_subprogramas(p):
    '''subprogramas : subprogramas subprograma
    | lambda'''

def p_subprograma(p):
    '''subprograma : funcion
    | procedimiento'''

#           ---/Procedimiento/---
def p_procedimiento(p):
    '''procedimiento : pcabecera pcabecera2 tkSemiColon procedimiento2'''

def p_pcabecera(p):
    '''pcabecera : tkProcedure id'''
    p.parser.actual.insertar_elemento(clases.C_ambito(p[2],p.parser.actual,"procedure"))
    p.parser.actual = p.parser.actual.elementos[p[2]]
    p.head = p.root.find("subprogram")
    p.head = icml.e.SubElement(p.head,"procedure")
    p.head.set("name",p[2])

def p_pcabecera2(p):
    '''pcabecera2 : parametros'''

def p_procedimiento2(p):
    '''procedimiento2 : declaraciones cuerpo_subprograma'''
    p.parser.actual = p.parser.actual.padre

#           ---/Funcion/---
def p_funcion(p):
    '''funcion : fcabecera fcabecera2 tkSemiColon funcion2'''
    icml.Crear_Cuerpo(p.cabezal,"result",[("type",p[2])])

def p_fcabecera(p):
    '''fcabecera : tkFunction id'''
    p.parser.actual.insertar_elemento(clases.C_ambito(p[2],p.parser.actual,"function"))
    p.parser.actual = p.parser.actual.elementos[p[2]]
    p.head = p.root.find("subprogram")
    p.head = icml.e.SubElement(p.head,"function")
    p.head.set("name",p[2])
    p.cabezal = p.head
    p[0] = p[2]

def p_fcabecera2(p):
    '''fcabecera2 : parametros tkColon tipos'''
    p.parser.actual.insertar_elemento(clases.C_elemento("result","result",p[3].tipo_dato,None,p[3].dimension))
    p.parser.actual.tipo_dato = p[3].tipo_dato
    p[0] = p[3].tipo_dato

def p_funcion2(p):
    '''funcion2 : declaraciones cuerpo_subprograma'''
    p.parser.actual = p.parser.actual.padre

def p_cuerpo_subprograma(p):
    '''cuerpo_subprograma : sentencia tkSemiColon
    | tkBegin sentencias tkEnd tkSemiColon'''
#______________________________________________________________________________#
#   ########################################################################   #
#                           CUERPO DEL PROGRAMA!!!                             #
#   ########################################################################   #
def p_sentencias(p):
    '''sentencias : sentencias option sentencia option
    | sentencia'''

def p_option(p):
    '''option : lambda
    | tkSemiColon'''

def p_sentencia(p):
    '''sentencia : asignacion
    | if
    | case
    | for
    | while
    | repeat
    | llamado lambda'''
    if len(p)==3:
        if p[1].tipo_token == "function": error.error15(p)
        else: p.head.insert((len(p.head.getchildren())),p[1].fruta)

#--------------Comienza la ramificacion dentro del codigo----------------------#
#______________________________________________________________________________#
#Asignacion a una variable de una porcion de codigo
def p_asignacion(p):
    '''asignacion : id tkAssign expresion'''
    fruta = None
    if not(p[1].__class__ == type("str")):
        fruta = icml.e.Element("index")
        fruta.insert(0,p[1].fruta)
        p[1] = p[1].nombre
    if not(p.parser.actual.buscar_elemento(p[1])[0]): error.error3(p)
    else : #Si existe id
        if p.parser.actual.buscar_elemento(p[1])[1].tipo_token == "const": error.error11(p)
        else:
            p[0] = icml.e.SubElement(p.head,"exp")
            p[0].set("op",p[2])
            p[2] = icml.e.SubElement(p[0],"lvalue")
            p[2].set("id",p[1])
            if not (fruta == None):
                p[2].insert(0,fruta)
                fruta = None
            p[0].insert(2,p[3].fruta)
            if (p.parser.actual.tipo_token == "function") and (p[1] == p.parser.actual.nombre): #Si esta aplicando el result
                if not (p.parser.actual.elementos["result"].tipo_dato == p[3].tipo_dato): error.error19(p)
            elif not(clases.Compatibilidad_tipos(p.parser.actual.buscar_elemento(p[1])[1].tipo_dato, p[3].tipo_dato)):
                if p.parser.actual.buscar_elemento(p[1])[1].tipo_dato == "array":
                    if not(clases.Compatibilidad_tipos(p.parser.actual.buscar_elemento(p[1])[1].oftype,p[3].tipo_dato)): error.error10(p)
            elif not((p.parser.actual.buscar_elemento(p[1])[1].tipo_dato == clases.Precedencia_tipos(p.parser.actual.buscar_elemento(p[1])[1].tipo_dato,p[3].tipo_dato))): error.error10(p)
#______________________________________________________________________________#
# Expresiones... parte atomica del codigo
def p_expresion(p):
    '''expresion : operacion
    | llamado
    | tkMinus operacion'''
    if len(p) == 2: p[0] = p[1]
    else:
        cabezal = icml.e.Element("minus")
        cabezal.insert(0,p[2].fruta)
        p[0] = p[2]
        p[0].fruta = cabezal

def p_operacion(p): #Ciclo completo para cada operacion //Sube un objeto...
    '''operacion : elemento
    | llamado
    | operacion tkMinus operacion
    | operacion tkPlus operacion
    | operacion tkMod operacion
    | operacion tkDiv operacion
    | operacion tkOr operacion
    | operacion tkAnd operacion
    | operacion tkXor operacion
    | operacion tkNot operacion
    | operacion tkEqual operacion
    | operacion tkNotEqual operacion
    | operacion tkGreater operacion
    | operacion tkLower operacion
    | operacion tkGreaterEqual operacion
    | operacion tkLowerEqual operacion
    | tkLparen operacion tkRparen  lambda'''
    if len(p)==2:
        p[0] = p[1]
        if not(p[1].tipo_token == "function"):
            p[0].fruta = icml.e.Element("exp")
            p[0].fruta.set("id",p[1].nombre)
    elif len(p)==4:
        p[0] = clases.C_elemento("incompatible","incompatible","boolean",None,None)
        if not (clases.Compatibilidad_tipos(p[1].tipo_dato,p[3].tipo_dato)): error.error10b(p)
        else: #Si son compatibles las dos operaciones que llegan
            if p[1].tipo_dato in clases.Numericos: tmp = "numerico"
            elif p[1].tipo_dato in clases.Cadenas: tmp = "cadena"
            elif p[1].tipo_dato == "boolean": tmp = "booleano" # en tmp se guarda el nombre de la lista de donde la vamos a buscar
            if not(clases.Compatibilidad_operador(tmp,p[2])): error.error13(p,tmp)
            elif p[2] in ['=','<>','<','>']: p[0] = clases.C_elemento("reduccion","reduccion","boolean",None,None)
            elif p[2] in ['or','and','not','xor'] and (p[1].tipo_dato == "boolean" and p[3].tipo_dato == "boolean"): p[0] = clases.C_elemento("reduccion","reduccion","boolean",None,None)
            else: p[0] = clases.C_elemento("reduccion","reduccion",clases.Precedencia_tipos(p[1].tipo_dato,p[3].tipo_dato),None,None)
            if p[2] in ["/"]: p[0].tipo_dato = "real"
        #Creacion de la parte que se colgara mas adelante del arbol.
        p[0].fruta= icml.e.Element("exp")
        p[0].fruta.set("op",str(p[2]))
        p[0].fruta.insert(1,p[1].fruta)
        p[0].fruta.insert(2,p[3].fruta)
    elif len(p)==5: p[0]=p[2]
#______________________________________________________________________________#
#   Llamado a una funcion o procedimiento
def p_llamado(p):
    '''llamado : id tkLparen lista_parametros tkRparen'''
    p[3].reverse()
    if p.parser.actual.buscar_elemento(p[1])[0]:
        if p.parser.actual.elementos[p[1]].tipo_token in ["function","procedure"]: #Que ID sea Funcion o Procedimiento
            if len(p[3]) == len(p.parser.actual.elementos[p[1]].parametros): #Que tengan la misma cantidad de parametros
                p[0]= p.parser.actual.buscar_elemento(p[1])[1]
                p[0].fruta = icml.e.Element("call")
                p[0].fruta.set(p.parser.actual.elementos[p[1]].tipo_token,p[1])
                for pos in range(len(p[3])):
                        p[3][pos].fruta.tag = "param"
                        p[0].fruta.insert(0,p[3][pos].fruta)
                        for par in p.parser.actual.elementos[p[1]].parametros.values():
                            if ((par.posicion == pos) and not(clases.Compatibilidad_tipos(par.tipo_dato,p[3][pos].tipo_dato))): error.error14(p)
            else:
                error.error5(p)
                p[0].fruta = icml.e.Element("llamado_incorrecto")
        else: error.error6(p)
    else: error.error2(p)
    p[0] = p.parser.actual.buscar_elemento(p[1])[1]

def p_lista_parametros(p):
    '''lista_parametros : lista_parametros tkComma operacion
    | operacion'''
    if len(p)==2: p[0] = [p[1]]
    else:
        p[0] = p[1]
        p[0].append(p[3])
#______________________________________________________________________________#
# IF
def p_if(p):     #Linea basica del IF
    '''if : if_head bucle if2'''
    p.head = p.head_padre.pop()

def p_if_head(p):
    '''if_head : tkIf condicion tkThen'''
    if not (p[2].tipo_dato == "boolean"): error.error7(p)
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"if")
    p[2].fruta.tag = "condition"
    p.head.insert(1,p[2].fruta)

def p_if2(p):   #Si deseamos ademas el Else
    '''if2 : else_tk bucle
    | lambda'''
    if len(p)==3: p.head = p.head_padre.pop()
#______________________________________________________________________________#
#   -FOR-
def p_for(p):
    '''for : for_head bucle''' # Simplemente: FOR X := 1 TO 2 DO
    p.head = p.head_padre.pop()
    p.for_id.pop()

def p_for_head(p):
    '''for_head : tkFor id tkAssign operacion tkTo operacion tkDo'''
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"for")
    p.cabeza = icml.e.SubElement(p.head,"params")
    p.cabeza.insert(0,icml.Crear_Cuerpo_Libre("param",[("id",p[2])]))
    p[4].fruta.tag,p[6].fruta.tag = "param_init","param_end"
    p.cabeza.insert(1,p[4].fruta)
    p.cabeza.insert(2,p[6].fruta)

    if not(p.parser.actual.buscar_elemento(p[2])[0]): error.error3b(p,p[2])
    elif not(p.parser.actual.buscar_elemento(p[2])[1].tipo_dato in ['integer', 'byte']): error.error12(p)
    if not(p[4].tipo_dato in ['integer','byte']): error.error12(p)
    if not(p[6].tipo_dato in ['integer','byte']): error.error12(p)
    if p[2] in p.for_id: error.error22(p)
    p.for_id.append(p[2])
#______________________________________________________________________________#
#   -WHILE- (Regla n50)
def p_while(p):
    '''while : while_head tkDo bucle'''
    p.head = p.head_padre.pop()

def p_while_head(p):
    '''while_head : tkWhile condicion'''
    if not(p[2].tipo_dato == 'boolean'): error.error8(p)
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"while")
    p[2].fruta.tag = "condition"
    p.head.insert(1,p[2].fruta)
#______________________________________________________________________________#
#   -REPEAT-
def p_repeat(p):
    '''repeat : repeat_tk sentencias tkUntil condicion'''
    if not(p[4].tipo_dato == 'boolean'): error.error9(p)
    p[4].fruta.tag = "condition"
    p.head.insert(0,p[4].fruta)
    p.head = p.head_padre.pop()

def p_repeat_tk(p):
    '''repeat_tk : tkRepeat'''
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"repeat")
#______________________________________________________________________________#
#   -CASE-
def p_case(p): #Comienza el case y armar el esqueleto
    '''case : case_head tkOf lista_constantes cierre tkEnd'''
    if not(clases.Compatibilidad_tipos(p[1],p[3])): error.error17(p)
    p.head = p.head_padre.pop()

def p_case_head(p): #Aca se coloca el selector (ID)...//Asi es mas entendible
    '''case_head : tkCase id'''
    if not(p.parser.actual.buscar_elemento(p[2])[0]):
        p[0] = "Variable sin declarar"
        error.error18(p)
    else:
        p[0] = p.parser.actual.buscar_elemento(p[2])[1].tipo_dato
        if not(p[0] in ["char","integer","byte"]): error.error21(p)
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"case")
    p.head.set("var",p[2])

def p_lista_constantes(p):
    '''lista_constantes : constante_case lista_constantes
    | constante_case'''
    if len(p)==2: p[0] = p[1]
    elif clases.Compatibilidad_tipos(p[1],p[2]): p[0] = clases.Precedencia_tipos(p[1],p[2])
    else: error.error17b(p)

def p_constante_case(p):
    '''constante_case : red_valor tkColon bucle tkSemiColon'''
    p[0] = p[1].tipo_dato
    p.head = p.head_padre.pop()

def p_red_valor(p):
    '''red_valor : valor'''
    p[0] = p[1]
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"case_value")
    p.head.set("constante",p[1].nombre)

def p_cierre(p):
    '''cierre : else_tk bucle
    | lambda'''
    if len(p)==3: p.head = p.head_padre.pop()
#______________________________________________________________________________#
#Generic things!
def p_id(p):
    '''id : tkIdentifier
    | tkIdentifier tkPoint tkIdentifier
    | tkIdentifier tkLbrac operacion tkRbrac'''
    p[0] = p[1]
    if len(p)==4:
        if not(p.parser.actual.buscar_elemento(p[1])[0]): error.error1(p,p[1])
        elif not(p.parser.actual.buscar_elemento(p.parser.actual.buscar_elemento(p[1])[1].tipo_dato)[1].buscar_elemento(p[3])[0]): error.error1(p,str(p[1]+"."+p[3]))
        else: #Creamos variable fantasma...
            gost_reg = p.parser.actual.buscar_elemento(p.parser.actual.buscar_elemento(p[1])[1].tipo_dato)[1].buscar_elemento(p[3])[1]
            p[0] = str(p[1] + "." + p[3])#Perfeccionar luego. //controles a variable interna de type
            item = clases.C_elemento(p[0],"type",gost_reg.tipo_dato,None,gost_reg.dimension,gost_reg.oftype)
            p.parser.actual.insertar_elemento(item)
    if len(p)==5:
        if not(p.parser.actual.buscar_elemento(p[1])[0]): error.error1(p,p[1])
        elif not(clases.Compatibilidad_tipos(p[3].tipo_dato,"integer")): error.error21(p)
        else:
            p[0] = p.parser.actual.buscar_elemento(p[1])[1]
            p[0].fruta = p[3].fruta

def p_elemento(p): #Cualquier elemento que forme parte de una sentencia //SUBE COMO OBJETO
    '''elemento : valor
    | id lambda'''
    if len(p)==2:
        p[0] = p[1]       #Cuando Entra por Valor... Valor ya llega hecho un objeto
    if len(p)==3:                   #Cuando entra por Id.. lo buscamos y lo subimos como objeto
        if p.parser.actual.buscar_elemento(p[1])[0]: #[0:True/False,1:objeto buscado]
            p[0] = p.parser.actual.buscar_elemento(p[1])[1] #Buscamos el ID y devolvemos el objeto...
        else:
            p[0] = clases.C_elemento("No_Existe","No_Existe","No_Existe","No_Existe","No_Existe")
            error.error3(p)

def p_numero(p):
    '''numero : tkByte
    | tkInteger'''
    p[0] = p[1]

def p_bucle(p):
    '''bucle : sentencia
    | tkBegin sentencias tkEnd'''

def p_condicion(p):
    '''condicion : expresion'''
    p[0]= p[1]

def p_else_tk(p):
    '''else_tk : tkElse'''
    p.head_padre.append(p.head)
    p.head = icml.e.SubElement(p.head,"else")

def p_lambda(p):
    '''lambda : '''
    pass

def p_error(p): #En caso de obtener una falla dentro de la gramatica, salta por aca...
    print("Error Sintactico: token '" + p.value + "' en linea " + str(p.lineno))
    error.error23("Error Sintactico: token '" + p.value + "' en linea " + str(p.lineno))
# ############################################################################ #
#                              Fin de la gramatica                             #
# ############################################################################ #
#                                 MOTOR PARSER                                 #
print("--------------INICIO DEL ANALISIS SINTACTICO----------------")
y = yacc.yacc()
y.actual = clases.C_ambito("main",None,"main")
error.crear_txt()

while 1:                                    #Infinitamente ciclamos
   try:
       source_filename = 'Codigos_Fuentes\Codigo.pas'      #Seleccionamos el codigo .pas elegido
       source = open(source_filename, 'r')  #Lo habrimos para lectura
       code = source.read()                 #asignamos la info a CODE
       source.close()                       #cerramos el archivo

   except EOFError:                         #Cuando termine el .pas
       break                                #fin del while
   if not code:
       continue                             #Si no, que continue
   result = y.parse(code, tracking=True)                #Aqui le vamos tirando los pedazos :D
   if result == None:
       break
   print result
#llamamos a Matenimiento para limpiar los .pyc
clean.Eliminar("*.pyc")
